package cc.rengu.igas.channel.ncqs.core.realize.impl;

import cc.rengu.igas.channel.ncqs.core.realize.NcqsEncSignService;
import cc.rengu.oltp.service.common.entity.CertInfo;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import org.apache.commons.codec.binary.Base64;

import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.List;

/**
 * 签名服务实现 on 2019/10/9.
 */
public class NcqsEncSignServiceImpl implements NcqsEncSignService {

    private static final String algorAES = "AES";
    private static final String algorRSA2 = "SHA256RSA";
    private static final String charset = "UTF-8";
    RgLogger rgLog = RgLog.getLogger(this.getClass().getName());

    @Override
    public String generateSignString(CertInfo certInfo, String signData) throws Exception {

        if ("0".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            if (certInfo.getAlgorithmType().contains("RSA")) {
                RSAPrivateKey privateKey = RSAUtil.getPrivateKeyFromBase64String(certInfo.getCertValue());
                return RSAUtil.rsaSignWithSha256(privateKey, signData.getBytes());
            } else if (certInfo.getAlgorithmType().contains("SM2")) {
                //国密算法
                rgLog.debug("国密签名算法CertSaveType:<{}>,", certInfo.getCertSaveType());
                return SM2Util.sm2SignWithSm3(certInfo.getCertValue(), certInfo.getCertId().getBytes(), signData.getBytes());
            } else {
                rgLog.debug("暂不支持签名算法CertSaveType:<{}>,", certInfo.getCertSaveType());
                return null;
            }
        } else if ("1".equals(certInfo.getCertSaveType())) {
            //调用加密机需自己客户化
            return null;
        } else if ("2".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            List<String> aliasList = RSAUtil.getCertAliasFromPfxCertFile(certInfo.getCertSavePath(), certInfo.getCertPassword());
            RSAPrivateKey privateKey = RSAUtil.getPrivateKeyFromCertFile(certInfo.getCertSavePath(), aliasList.get(0), certInfo.getCertPassword());
            return RSAUtil.generateSignString(signData, privateKey, certInfo.getAlgorithmType(), charset);
        } else {
            rgLog.debug("不支持密钥存储类型CertSaveType:<{}>,", certInfo.getCertSaveType());
            return null;
        }
    }

    /**
     * 校验数字签名
     *
     * @param certInfo  证书信息
     * @param sign      数字签名
     * @param signBlock 生成数字签名的字符串
     * @return true-成功，false-失败
     */
    @Override
    public boolean verifySignString(CertInfo certInfo, String sign, String signBlock) throws Exception {
        // 判断证书/密钥类型,通过软加密还是硬加密方式（0-本地数据库存储,1-加密机,2-本地文件）
        if ("0".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            if (certInfo.getAlgorithmType().contains("RSA")) {
                RSAPublicKey publicKey = RSAUtil.getPublicKeyFromBase64String(certInfo.getCertValue());
                return RSAUtil.rsaVerifyWithSha256(publicKey, signBlock.getBytes(), sign);
            } else if (certInfo.getAlgorithmType().contains("SM2")) {
                // 支持国密算法
                rgLog.debug("国密签名算法CertSaveType:<{}>,", certInfo.getCertSaveType());
                return SM2Util.sm2VerifyWithSm3(certInfo.getCertValue(), certInfo.getCertId().getBytes(), signBlock.getBytes(), sign);
            } else {
                rgLog.debug("暂不支持签名算法CertSaveType:<{}>,", certInfo.getCertSaveType());
                return false;
            }
        } else if ("1".equals(certInfo.getCertSaveType())) {
            //需要自己客户化
            return false;
        } else if ("2".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            RSAPublicKey publicKey = RSAUtil.getPublicKeyFromCertFile(certInfo.getCertSavePath());
            return RSAUtil.verifySignString(signBlock, sign, publicKey, certInfo.getAlgorithmType(), charset);
        }
        return false;
    }

    /**
     * 生成加密字符串
     *
     * @param certInfo 证书信息
     * @param data     需要加密的字符串
     * @param encKey   对称密钥
     * @return 加密后的字符串
     */
    @Override
    public String encryptedInfo(CertInfo certInfo, String data, String encKey) throws Exception {
        if ("0".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            /*if (certInfo.getAlgorithmType().contains("RSA")) {
                return Base64.encodeBase64String(DES3Util.cbcModeEncrypt(encKey.getBytes(), data.getBytes()));
            } else*/
            if (certInfo.getAlgorithmType().contains("SM2")) {
                //支持国密算法
                rgLog.debug("国密加密SM4");
                return Base64.encodeBase64String(SM4Util.sm4CbcEncrypt(encKey, data, "NoPadding"));
            } else {
                rgLog.debug("暂不支持软加密的算法类型:<{}>,", certInfo.getAlgorithmType());
            }
        } else if ("1".equals(certInfo.getCertSaveType())) {
            //调用加密机需自己客户化
            return null;
        } else {
            rgLog.debug("不支持密钥存储类型CertSaveType:<{}>,", certInfo.getCertSaveType());
            return null;
        }
        return null;
    }

    /**
     * 解密字符串
     *
     * @param certInfo 证书信息
     * @param encData  待解密数据
     * @param encKey   对称密钥
     * @return 解密后的字符串
     */
    @Override
    public String decryptedInfo(CertInfo certInfo, String encData, String encKey) throws Exception {
        if ("0".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            /*if (certInfo.getAlgorithmType().contains("RSA")) {
                byte[] sensInfE = Base64.decodeBase64(encData);
                byte[] sensInf = DES3Util.desEdeCbcDecrypt(encKey.getBytes(), sensInfE);
                return new String(sensInf);
            } else*/
            if (certInfo.getAlgorithmType().contains("SM2")) {
                //支持国密算法
                return SM4Util.sm4CbcDecrypt(encKey, encData, "NoPadding");
            } else {
                rgLog.debug("暂不支持软加密的算法类型:<{}>,", certInfo.getAlgorithmType());
            }
        } else if ("1".equals(certInfo.getCertSaveType())) {
            //调用加密机需自己客户化
            return null;
        } else {
            rgLog.debug("不支持密钥存储类型CertSaveType:<{}>,", certInfo.getCertSaveType());
            return null;
        }
        return null;
    }

    /**
     * 加密对称密钥
     *
     * @param certInfo 证书
     * @param encKey   对称密钥
     * @return 加密后的对称密钥
     * @throws Exception 异常
     */
    @Override
    public String encryptedEncKey(CertInfo certInfo, String encKey) throws Exception {
        if ("0".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软加密,算法类型:<{}>,", certInfo.getAlgorithmType());
            if (certInfo.getAlgorithmType().contains("RSA")) {
                RSAPublicKey publicKey = RSAUtil.getPublicKeyFromBase64String(certInfo.getCertValue());
                byte[] encKeyE = RSAUtil.rsaEcbEncrypt(publicKey, encKey.getBytes(), "PKCS1Padding");
                return Base64.encodeBase64String(encKeyE);
            } else if (certInfo.getAlgorithmType().contains("SM2")) {
                //支持国密算法用SM4进行加密
                return SM2Util.SM2KeyEncrypt(certInfo.getCertValue(), encKey.getBytes());
            } else {
                rgLog.debug("暂不支持软加密的算法类型:<{}>,", certInfo.getAlgorithmType());
            }
        } else if ("1".equals(certInfo.getCertSaveType())) {
            //调用加密机需自己客户化
            return null;
        } else {
            rgLog.debug("不支持密钥存储类型CertSaveType:<{}>,", certInfo.getCertSaveType());
            return null;
        }
        return null;
    }

    /**
     * 解密对称密钥
     *
     * @param certInfo 证书
     * @param encKey   对称密钥
     * @return 解密后的对称密钥
     * @throws Exception 异常
     */
    @Override
    public String decryptedEncKey(CertInfo certInfo, String encKey) throws Exception {

        if ("0".equals(certInfo.getCertSaveType())) {
            rgLog.debug("使用软解密,算法类型:<{}>,", certInfo.getAlgorithmType());
            if (certInfo.getAlgorithmType().contains("RSA")) {
                RSAPrivateKey privateKey = RSAUtil.getPrivateKeyFromBase64String(certInfo.getCertValue());
                byte[] encKeyE = Base64.decodeBase64(encKey);
                byte[] result = RSAUtil.rsaEcbDecrypt(privateKey, encKeyE, "PKCS1Padding");
                return new String(result);
            } else if (certInfo.getAlgorithmType().contains("SM2")) {
                //支持国密算法
                byte[] result = SM2Util.SM2KeyDecrypt(certInfo.getCertValue(), encKey);
                return new String(result);
            } else {
                rgLog.debug("暂不支持软解密的算法类型:<{}>,", certInfo.getAlgorithmType());
            }
        } else if ("1".equals(certInfo.getCertSaveType())) {
            //调用加密机需自己客户化
            return null;
        } else {
            rgLog.debug("不支持密钥存储类型CertSaveType:<{}>,", certInfo.getCertSaveType());
            return null;
        }
        return null;
    }

}
